package gweb

import (
	"fmt"
	"strings"
)

// DB的泛型版本
type QuerySet[T any] struct {
	*DB
}

func (qs *QuerySet[T]) Clone() *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Clone()}
}

func (qs *QuerySet[T]) Conds(conds map[string]any) *QuerySet[T] {
	db := qs.DB.Clone()
	for k, v := range conds {
		vStr := fmt.Sprintf("%v", v)
		if vStr == "<nil>" {
			db = db.Where(fmt.Sprintf("`%s` IS NULL", k))
		} else {
			db = db.Where(fmt.Sprintf("`%s`=?", k), v)
		}
	}
	return &QuerySet[T]{DB: db}
}

func (qs *QuerySet[T]) Panic() *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Panic()}
}

func (qs *QuerySet[T]) Table(name string) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Table(name)}
}

func (qs *QuerySet[T]) Where(query any, args ...any) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Where(query, args...)}
}

func (qs *QuerySet[T]) Or(query interface{}, args ...interface{}) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Or(query, args...)}
}

func (qs *QuerySet[T]) Limit(limit int) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Limit(limit)}
}

func (qs *QuerySet[T]) Offset(offset int) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Offset(offset)}
}

func (qs *QuerySet[T]) Order(fields ...string) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Order(strings.Join(fields, ","))}
}

func (qs *QuerySet[T]) Preload(query string, args ...interface{}) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Preload(query, args...)}
}

func (qs *QuerySet[T]) Select(query interface{}, args ...interface{}) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Select(query, args...)}
}

func (qs *QuerySet[T]) FindAll() ([]T, error) {
	var records = []T{}
	if err := qs.DB.Find(&records); err != nil {
		return records, err
	}
	return records, nil
}

func (qs *QuerySet[T]) ForEach(callback func(record T) error) error {
	records, err := qs.FindAll()
	if err != nil {
		return err
	}
	for _, record := range records {
		if err := callback(record); err != nil {
			break
		}
	}
	return nil
}

func (qs *QuerySet[T]) Omit(columns ...string) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Omit(columns...)}
}

func (qs *QuerySet[T]) GetFirst(conds ...any) (*T, error) {
	var record T
	if err := qs.DB.First(&record, conds...); err != nil {
		return nil, err
	}
	return &record, nil
}

func (qs *QuerySet[T]) Distinct(args ...interface{}) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Distinct(args...)}
}

// group by 分组查询，在原有的基础上，允许将group字段分散在不同的地方
func (qs *QuerySet[T]) Group(fields ...string) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Group(strings.Join(fields, ","))}
}

func (qs *QuerySet[T]) Raw(sql string, values ...interface{}) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Raw(sql, values...)}
}

func (qs *QuerySet[T]) Run(fc func(qs *QuerySet[T])) *QuerySet[T] {
	fc(qs)
	return qs
}

func (qs *QuerySet[T]) Joins(query string, args ...interface{}) *QuerySet[T] {
	return &QuerySet[T]{DB: qs.DB.Joins(query, args...)}
}

func (qs *QuerySet[T]) FindOrPaginate2(pi int, ps int) (any, error) {
	var records []T
	return qs.DB.FindOrPaginate(&records, pi, ps)
}

func (qs *QuerySet[T]) Paginate2(pi int, ps int) (*Pagination[[]T], error) {
	var records []T
	p, err := qs.DB.Paginate(&records, pi, ps)
	return &Pagination[[]T]{
		PageIndex: p.PageIndex,
		PageSize:  p.PageSize,
		Total:     p.Total,
		List:      records,
	}, err
}

func Q[T any](db *DB) *QuerySet[T] {
	var m T
	return &QuerySet[T]{DB: db.Model(m)}
}
